// -----------------------------------------------------------------------------
//
// GAMCS -- Generalized Agent Model and Computer Simulation
//
// Copyright (C) 2013-2014, Andy Huang  <andyspider@126.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// -----------------------------------------------------------------------------
//
// Created on: Feb 21, 2014
//
// -----------------------------------------------------------------------------

#include <stdio.h>
#include "gamcs/CDotViewer.h"
#include "gamcs/Agent.h"
#include "gamcs/Storage.h"
#include "gamcs/StateInfoParser.h"

namespace gamcs
{

/**
 * @brief The default constructor.
 *
 * @param [in] sg the storage to be viewed
 */
CDotViewer::CDotViewer(Storage *sg) :
		DotViewer(sg), last_state(Agent::INVALID_STATE), last_action(
				Agent::INVALID_ACTION)
{
}

/**
 * @brief The default destructor.
 */
CDotViewer::~CDotViewer()
{
}

/**
 * @brief View the whole memory in graphviz dot style cleanly.
 *
 * @param [in] file where to output the view, NULL for standard output
 * @dot
 * digraph Example
 * {
 * label="memory Example\ndiscount rate: 0.90, accuracy: 0.01, #states: 7, #links: 11"
 * node [color=black,shape=circle]
 * rank="same"
 *
 * st8 [label="8"]
 * st8 -> st7 [label="<1, -2>"]
 *
 * st7 [label="7"]
 * st7 -> st6 [label="<1, -2>"]
 * st7 -> st8 [label="<2, -1>"]
 *
 * st6 [label="6"]
 * st6 -> st5 [label="<1, -2>"]
 * st6 -> st7 [label="<2, -1>"]
 *
 * st5 [label="5"]
 * st5 -> st6 [label="<2, -1>"]
 *
 * st4 [label="4"]
 * st4 -> st5 [label="<2, -1>"]
 * st4 -> st3 [label="<1, -2>"]
 *
 * st2 [label="2"]
 * st2 -> st3 [label="<2, -1>"]
 *
 * st3 [label="3"]
 * st3 -> st4 [label="<2, -1>"]
 * st3 -> st2 [label="<1, -2>"]
 * }
 * @enddot
 */
void CDotViewer::view(const char *file)
{
	int re = storage->open(Storage::O_READ);
	if (re != 0)    // connect failed
	{
		WARNNING("DotViewer CleanShow(): open storage failed!\n");
		return;
	}

	FILE *output = NULL;
	if (file == NULL)
		output = stdout;
	else
		output = fopen(file, "w");

	fprintf(output,
			"/* This is the dot file of agent memory automaticlly generated by DotViewer */\n\n");

	// generate dot syntax
	fprintf(output, "digraph %s \n{\n", storage->getMemoryName().c_str());

	// memory info
	struct Memory_Info *memif = storage->getMemoryInfo();
	if (memif != NULL)
	{
		fprintf(output,
				"label=\"memory %s\\ndiscount rate: %.2f, accuracy: %.2f, #states: %" UINT32_FMT ", #links: %" UINT32_FMT "\"\n",
				storage->getMemoryName().c_str(), memif->discount_rate,
				memif->accuracy, memif->state_num, memif->lk_num);
		// store last status
		last_state = memif->last_st;
		last_action = memif->last_act;
		free(memif);    // free it, the memory struct are not a substaintial struct for running, it's just used to store meta-memory information
	}
	else
	{
		fprintf(output, "Memory not found in storage!\n");
		fprintf(output, "}\n");    // digraph
		storage->close();
		return;
	}

	// states info
	fprintf(output, "node [color=black,shape=circle]\n");
	fprintf(output, "rank=\"same\"\n");
	// print states info
	Agent::State st = storage->firstState();
	while (st != Agent::INVALID_STATE)    // get state value
	{
		struct State_Info_Header *stif = storage->getStateInfo(st);
		if (stif != NULL)
		{
			cleanDotStateInfo(stif, output);
			free(stif);
			st = storage->nextState();
		}
		else
			ERROR("Show(): state: %" ST_FMT " information is NULL!\n", st);
	}
	fprintf(output, "}\n");    // digraph
	storage->close();
}

/**
 * @brief View a state information in dot style cleanly.
 *
 * @param [in] sthd the state information
 * @param [in] output the stream to output the view, NULL for standard output
 */
void CDotViewer::cleanDotStateInfo(const struct State_Info_Header *sthd,
		FILE *output) const
{
	/* generated state example:
	 *
	 * st9 [label="9"]
	 *
	 * st9 -> st8 [label="<0, -1>"]
	 * st9 -> st10 [label="<0, 1>"]
	 */
	if (sthd == NULL)
		return;

	fprintf(output, "\nst%s [label=\"%" ST_FMT "\"]\n", int2String(sthd->st).c_str(), sthd->st);

	StateInfoParser sparser(sthd);
	Action_Info_Header *athd = NULL;
	EnvAction_Info *eaif = NULL;

	athd = sparser.firstAct();
	while (athd != NULL)
	{
		eaif = sparser.firstEat();
		while (eaif != NULL)
		{
			fprintf(output, "st%s -> st%s [label=\"<%" ACT_FMT ", %" ACT_FMT ">\"]\n", int2String(sthd->st).c_str(),
					int2String(eaif->nst).c_str(), athd->act, eaif->eat);

			eaif = sparser.nextEat();
		}

		athd = sparser.nextAct();
	}
}

} /* namespace gamcs */
